using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;

namespace Advanced_Terrain
{
   public class Disc : DrawableGameComponent
    {
       //public CustomDisc DiskInfo;
       private float Putter=0;
       public float PowerMultiplier;
       private ContentManager _content;
       private Model _model;
       Matrix[] _boneTransforms;
       float Spinning = 0f;
       int StepCounter = 0;
       public float SpinFactor = 3f;
       public Vector3 Position;
       public Vector3 Direction;
       public Vector3 BasketPosition;
       float SpeedMultiplier = .8f;
       Vector3 PreviosPosition;
       private Texture2D _Texture;
       public float Scale = .015f;
       //public float Scale = .055f;
       public Boolean Flying = true;
       public float DistanceToTree;
       float DistanceToBasket;
       int CanDeflect = 0;
       public float BalancingCoeffiecent = 1f;
       float OriginalBalancingCoeffiecent = 1f;
       public Boolean Rolling = false;
       Vector3 DiscUp = new Vector3(0, 0, 0);
       Vector3 NewPosition;
       Boolean PlayTink = true;
       public float TerrainHeight;
       Boolean FlipBalancing = false;
       private float FlightTimeMult = 0f;
       
       
       //Vector3 discRotation = new Vector3(0, 0, 0);

       //PHYSICS
       public float MaxVelocity =100;
       public Quaternion Rotation = Quaternion.Identity;
       public Vector3 Velocity = Vector3.Zero;
       public float DragCoffiecient = .8f;
       public float LiftCoeffiecient = 1.8f;
       Vector3 AppliedVelocity = new Vector3(0, 0, 0);
       public float Pitch = 0;
       public float Roll = 0;
       public float Yaw = 0;
       //CONSTANTS
       Vector3 Gravity = new Vector3(0.0f, -9.8f, 0.0f);
       
        public Disc(Game game, ContentManager content)
            : base(game)
        {
            _content = content;
        }
        public void SetTexture(string texture)
        {
            _Texture = _content.Load<Texture2D>(@"DiscTextures/"+texture);
        }
        protected override void LoadGraphicsContent(bool loadAllContent)
        {
            _model = _content.Load<Model>("frisbee");
            // Allocate the transform matrix array.
            _boneTransforms = new Matrix[_model.Bones.Count];
            //_Texture = _content.Load<Texture2D>("Innova");
            //rotate the model 90 degrees
            //_model.Root.Transform *= Matrix.CreateRotationX(MathHelper.ToRadians(90));

            base.LoadGraphicsContent(loadAllContent);
        }

        public override void Draw(GameTime gameTime)
        {
            

            _model.CopyAbsoluteBoneTransformsTo(_boneTransforms);
            // Draw the model.
            foreach (ModelMesh mesh in _model.Meshes)
            {   
                foreach (BasicEffect effect in mesh.Effects)
                {
                    effect.Begin();
                    effect.Projection = CameraProperties.projectionMatrix;
                    effect.World = _boneTransforms[mesh.ParentBone.Index] * Matrix.CreateScale(Scale) * Matrix.CreateFromQuaternion(Rotation) * Matrix.CreateFromAxisAngle(DiscUp, Spinning) * Matrix.CreateTranslation(Position);
                    effect.View = CameraProperties.View;
                    effect.TextureEnabled = true;
                    effect.Texture = _Texture;
                    effect.EnableDefaultLighting();
                    effect.End();
                }
                
               
                mesh.Draw();
            }

            base.Draw(gameTime);
        }
       public void UpdatePosition(GameTime gameTime)
       {
           FlightTimeMult += .004f;
           
               this.DiscUp = Vector3.Transform(Vector3.Up, Matrix.CreateFromQuaternion(Rotation));
               Spinning = Spinning + (.8f * SpinFactor);
               if (this.Flying == true)
               {

                   this.Direction = Position - PreviosPosition;
                   this.PreviosPosition = Position;
                   ApplyRotations();
                   ApplyGravity(gameTime);
                   CheckForWater();
                   if (this.Flying || this.Rolling)
                   {
                       CheckForOutOfBounds();
                   }
                   if (CameraProperties.CameraFloating != CameraProperties.CameraDeflection)
                       CheckForBasket(gameTime);
                   if (Position.Y - TerrainHeight < 10.5f)
                   {
                       CheckForTrees();
                   }
                   else
                   {
                       CameraProperties.CameraFloating = CameraProperties.CameraDiskFlying;
                       SpeedMultiplier = 1f;
                   }
                   if (CanDeflect > -1)
                       CanDeflect--;
               }
               if (Rolling == true)
               {
                   CheckForWater();
                   CheckForOutOfBounds();
                   CheckForTrees();
                   if(Rolling == true)
                        ApplyRolling();
                   
                   

               }
               Vector3 PositionTest = this.Position;
               if (Flying || Rolling)
               {
                   try
                   {

                       PositionTest = Position;
                       TerrainHeight = Game1.newTerrain.GetTerrainHeight(PositionTest.X, PositionTest.Z * -1);
                   }
                   catch
                   {
                       Flying = false;
                       Rolling = false;
                       Advanced_Terrain.Game1.GameState = Game1.GameStateOB;
                       ResetDisc();
                   }
               }
           
       }
       void ApplyGravity(GameTime gameTime)
       {
           Velocity.Y += ((Velocity.Z / MaxVelocity) * -5f) *(float)gameTime.ElapsedGameTime.Milliseconds / 1000 * SpeedMultiplier;
           Velocity.Z += (Velocity.Z * ((1 - DragCoffiecient) * -.8f)) * (float)gameTime.ElapsedGameTime.Milliseconds / 1000 * SpeedMultiplier;
           this.Position += (Vector3.Transform(Velocity, Rotation) * .0017f * SpeedMultiplier);
           this.Position.Y += (-9.8f * .00175f * SpeedMultiplier) + (((LiftCoeffiecient - (Velocity.Z / (-1 * MaxVelocity))) * -.045f) * SpeedMultiplier);

       }
       public void ApplyRotations()
       {
           if (Flying)
           {
                   Roll += BalancingCoeffiecent * SpeedMultiplier * .0017f;
                   if (Math.Abs(SpinFactor) > .2f)
                       SpinFactor -= .001f;

           } else
           {
               SpinFactor -= .0002f;
               if (SpinFactor < 0)
                   SpinFactor = 0;
           }

           Rotation = Quaternion.CreateFromYawPitchRoll(Yaw, Pitch, Roll);
           Rotation.Normalize();
       }
       public void ResetDisc()
       {
           Rotation = Quaternion.Identity;
           AppliedVelocity = new Vector3(0, 0, 0);
           Direction = new Vector3(0,0,0);
           Velocity = new Vector3(0,0,0);
           Pitch = 0;
           Yaw = 0;
           Roll = 0;
           SpinFactor = 3f;
           Rolling = false;
           PlayTink = true;
           TerrainHeight = 0;
           BalancingCoeffiecent = 1f;
           LiftCoeffiecient = 1.8f;
           ApplyRotations();
           MaxVelocity = 100;
           Putter = 0;
           CanDeflect = 25;
           //Flying = false;
       }
       void CheckForOutOfBounds()
       {
           
           try
           {
               if (!Rolling)
               {
                   if (Position.X < 1 || Position.X > 126 || Position.Z < -126 || Position.Z > -1)
                   {
                       Game1.GameState = Game1.GameStateOB;
                       Game1.Delay = 20;
                       this.Flying = false;
                       this.Rolling = false;
                   }
                   else
                   {
                       if (Position.Y < TerrainHeight)
                       {
                           this.Flying = false;
                           if (Roll > MathHelper.ToRadians(20) || Roll < MathHelper.ToRadians(-20))
                           {
                               Rolling = true;
                               StepCounter = 0;
                               Game1.GameState = Game1.GameStateNoCameraMove;
                               CameraProperties.CameraFloating = CameraProperties.CameraNotMoving;
                               CameraProperties.cameraPosition.Y += 15.5f;
                               //Velocity.X = 0;
                               //Velocity.Y = 0;
                               //Velocity *= SpeedMultiplier;
                               //CameraProperties.cameraPosition.Y += 2;
                           }
                           else
                           {
                               //CanDeflect = 0;

                               Game1.GameState = Game1.GameStatePreAiming;
                               this.Position.Y = TerrainHeight + .9f;
                               this.ResetDisc();
                           }
                       }
                   }
               }
           }
           catch
           {
               Flying = false;
               Rolling = false;
               Advanced_Terrain.Game1.GameState = Game1.GameStateOB;
               ResetDisc();
           }
       }
       public void CheckForTrees()
       {
           DistanceToTree = 99999;
           NewPosition = Position;
           NewPosition.Y = TerrainHeight-1;
           float TreeVertBottom =  0;
           float TreeVertTop = 0;
           float TreeHorMax = 0;
           float TreeHorMin = 0;
           //For loop for the billboards
           //foreach (Vector3 TreePos in Game1.treeList)
           //{

           //    if (Vector3.Distance(NewPosition, TreePos) < DistanceToTree)
           //        DistanceToTree = Vector3.Distance(NewPosition, TreePos);
           //}
           //For loop for the non-billboards
           int index = 0;
           float tempDistanceToTree;
           foreach (TreeClass TreePos in Game1.newTerrain.TreeClassList)
           {
               tempDistanceToTree = Vector3.Distance(NewPosition, TreePos.Position);
                   if (tempDistanceToTree > 100)
                   {
                       int indexof = Game1.newTerrain.TreeClassList.IndexOf(TreePos);
                       Game1.newTerrain.TreeClassList[indexof].UseLowPoly = true;
                   }
                   else
                   {
                       Game1.newTerrain.TreeClassList[index].UseLowPoly = false;
                   }
               if ( tempDistanceToTree< DistanceToTree)
               {
                    
                   switch (TreePos.TreeType)
                   {
                           //Willow
                       case 0:
                           {
                               TreeVertBottom = 0f;
                               TreeVertTop = .75f;
                               TreeHorMax = 4.5f;
                               TreeHorMin = .8f;
                               break;
                           }
                           //Pine
                       case 1:
                           {
                               TreeVertBottom = 0f;
                               TreeVertTop = 2f;
                               TreeHorMax = 3.5f;
                               TreeHorMin = .8f;

                               break;
                           }
                           //Birch
                       case 2:
                           {
                               TreeVertBottom = 0f;
                               TreeVertTop = 2f;
                               TreeHorMax = 2.75f;
                               TreeHorMin = .8f;

                               break;
                           }

                           //Gardenwood
                       case 3:
                           {
                               TreeVertBottom = 0f;
                               TreeVertTop = 5.25f;
                               TreeHorMax = 2.75f;
                               TreeHorMin = .8f;

                               break;
                           }


                   }
                   DistanceToTree = Vector3.Distance(NewPosition, TreePos.Position);
                   
               }
               index++;
           }
           if (!Rolling)
           {
               if (DistanceToTree < 6.5)
               {
                   if (CameraProperties.CameraFloating != CameraProperties.CameraDeflection)
                   {
                       if (CanDeflect < 0)
                       {
                           //CameraProperties.CameraFloating = CameraProperties.CameraDeflection;
                           //CameraProperties.cameraPosition = CameraProperties.cameraPosition - (this.Direction * 10);
                           //CameraProperties.cameraPosition.Y += 10;

                           //CameraProperties.CameraUp = Vector3.Up;
                           //SpeedMultiplier = 1f;
                       }
                   }
                   if (Position.Y - TerrainHeight > TreeVertTop)
                   {
                       if (DistanceToTree < TreeHorMax)
                       {
                           if (CanDeflect < 0)
                           {
                               Random DeflectionAngle = new Random();
                               int DA = DeflectionAngle.Next(-65, 65);
                                   float Deadening = 0;
                                   Deadening = DeflectionAngle.Next(50, 125);
                                   this.Velocity = this.Velocity * (Deadening / 150);
                                   Yaw = Yaw + MathHelper.ToRadians(DA);
                                   Pitch += DeflectionAngle.Next(-1, 1) * .025f;
                                   CanDeflect = 120;
                               
                           }                       
                       }
                   }
                   else
                   {
                       if (DistanceToTree < TreeHorMin)
                       {
                           if (CanDeflect < 0)
                           {
                               Random DeflectionAngle = new Random();
                               int DA = DeflectionAngle.Next(-120, 120);
                               DA = 8;
                               if (Math.Abs(DA) < 10)
                               {
                                   this.Velocity *= -1;
                                   this.Velocity = (this.Velocity / 2);
                                   if (this.Velocity.Y > 0)
                                       this.Velocity.Y *= -1;
                                   CanDeflect = 45;
                               }
                               else
                               {
                                   float Deadening = 0;
                                   Deadening = DeflectionAngle.Next(10, 100);
                                   this.Velocity = this.Velocity * (Deadening / 150);
                                   Yaw = Yaw + MathHelper.ToRadians(DA);
                                   Pitch += DeflectionAngle.Next(-1, 1);
                                   CanDeflect = 45;
                               }
                           }

                       }
                   }

               }
               else
               {

                   CameraProperties.CameraFloating = CameraProperties.CameraDiskFlying;
                   SpeedMultiplier = 1f;

               }
           
           }
           else
           {
               if (DistanceToTree < 1)
               {
                   Rolling = false;
                   this.ResetDisc();
                   Game1.GameState = Game1.GameStatePreAiming;
               }
           }
       }
       void CheckForBasket(GameTime gameTime)
       {
           Vector3 NewPosition = Position;
           NewPosition.Y = TerrainHeight;
           DistanceToBasket = Vector3.Distance(NewPosition, BasketPosition);
           if (DistanceToBasket <6 )
           {
               if (Position.Y - TerrainHeight > .4 - Putter && Position.Y - TerrainHeight < 1.3 + Putter)
               {
                   Advanced_Terrain.CameraProperties.CameraFloating = CameraProperties.CameraCloseToBasket;
                   this.SpeedMultiplier = .1f;
                   if (DistanceToBasket < .550)
                   {
                       if (Position.Y - TerrainHeight > .6 - Putter && Position.Y - TerrainHeight < 1.135 + Putter)
                       {

                           
                           float ClosestDistance = .6f + Putter;
                           Vector3 OriginalPosition = this.Position;
                           Vector3 OriginalVelocity = this.Velocity;
                           
                           do
                           {
                               
                               ApplyGravity(gameTime);
                               ApplyRotations();
                               NewPosition.Y = TerrainHeight;
                               if (Vector3.Distance(NewPosition, BasketPosition) < ClosestDistance)
                               {
                                   ClosestDistance = Vector3.Distance(NewPosition, BasketPosition);
                               }
                               

                            } while (DistanceToBasket < .550 + Putter && this.Position.Y > .4f - Putter);
                                   if (ClosestDistance > .530 + Putter)
                                   {
                                       if (PlayTink)
                                       {
                                           Game1.soundBank.PlayCue("GrazeChains");
                                           this.Flying = true;
                                           this.Yaw += MathHelper.ToRadians(120);
                                           this.Position = OriginalPosition;
                                           this.Roll -= MathHelper.ToRadians(30);
                                           this.Velocity = OriginalVelocity *.5f;
                                           ApplyRotations();
                                           ApplyGravity(gameTime);
                                           PlayTink = false;
                                       }

                                   }
                                   else
                                   {
                                       if (PlayTink)
                                       {
                                           Game1.soundBank.PlayCue("DiskStayingIn");
                                           PlayTink = false;
                                           Flying = false;
                                       }

                                   }
                               
                           if (!Flying)
                           {
                               Game1.Players[Game1.CurrentPlayer].InHole = true;
                               Game1.GameState = Game1.GameStateShakingChains;
                               //CameraProperties.CameraFloating = CameraProperties.CameraAnimatingChains;

                               Game1.Delay = 60;
                               this.Position = BasketPosition;
                               this.Position.Y += .75f;
                               this.Position.X += .1f;
                               this.Position.Z += .05f;
                               this.Roll = MathHelper.ToRadians(62);
                               ApplyRotations();
                               this.SpinFactor = 0;
                               //Game1.GameState = Game1.GameStateInBasket;
                               CameraProperties.cameraPosition = this.Position;
                               CameraProperties.cameraPosition.Y = this.TerrainHeight+ 4.5f;
                               
                               CameraProperties.cameraPosition.X = CameraProperties.cameraPosition.X + 7f;
                               CameraProperties.CameraFloating = CameraProperties.CameraAnimatingChains;
                           }
                           //this.ResetDisc();
                       }
                       else
                       {
                           if (Position.Y - TerrainHeight > .5 && Position.Y - TerrainHeight < .6)
                           {
                               if (PlayTink)
                               {
                                   Game1.soundBank.PlayCue("TinkBasket");
                                   this.Yaw += MathHelper.ToRadians(120);
                                   ApplyRotations();
                                   this.Velocity.Z *= .1f;
                                   ApplyGravity(gameTime);
                                   PlayTink = false;
                               }
                           }
                       }


                   }
                   
               }
           }
           else
           {
               if (CameraProperties.CameraFloating != CameraProperties.CameraDeflection)
               {
                   SpeedMultiplier = .8f;
                   CameraProperties.CameraFloating = CameraProperties.CameraDiskFlying;
               }
           }
       }
       void CheckForWater()
       {
           if (Position.Y < 5.1)
           {
               Game1.soundBank.PlayCue("DiscSplashInWater");
               Flying = false;
               Rolling = false;
               Advanced_Terrain.Game1.GameState = Game1.GameStateWater;
               ResetDisc();
           }


       }
       void ApplyRolling()
       {

           if (Roll > MathHelper.ToDegrees(90) || Roll < MathHelper.ToDegrees(-90))
           {
               Rolling = false;
           }
           this.Direction = this.Position - PreviosPosition;
           this.PreviosPosition = this.Position;
           this.Position.Y = TerrainHeight + .5f;
           Velocity += new Vector3(0, 0, .068f);
           if (Velocity.Z > -.00001f)
           {
               this.ResetDisc();
               Game1.GameState = Game1.GameStatePreAiming;
               Game1.Delay = 100;

           }
           if (StepCounter > 2)
           {
               Velocity.Z += this.Direction.Y * .05f;
           }
           else
               StepCounter++;

           ApplyRotations();
           if (SpinFactor < .0001)
           {
               this.ResetDisc();
               Game1.GameState = Game1.GameStatePreAiming;
               Game1.Delay = 100;
           }
           if (Math.Abs(Roll) < MathHelper.ToRadians(15) || Math.Abs(Roll) > MathHelper.ToRadians(165) )
           {
               this.ResetDisc();
               Game1.GameState = Game1.GameStatePreAiming; 
               Game1.Delay = 100;
           }
           
           
           if (Rolling)
           {
               if (Roll > 0 && Roll <= MathHelper.ToRadians(90))
               {
                   Roll += ((float)Math.Cos(Roll) * -.009000f);
                   Yaw += (float)Math.Sin(Roll) * -.025f;
               }
               if (Roll < 0 && Roll >= MathHelper.ToRadians(-90))
               {
                   Roll += ((float)Math.Cos(Roll) * -.009000f) * -1;
                   Yaw += (float)Math.Sin(Roll) * -.025f;
               }
               if (Roll > MathHelper.ToRadians(90) && Roll <= MathHelper.ToRadians(180))
               {
                   Roll += ((float)Math.Cos(Roll) * -.009000f);
                   Yaw += (float)Math.Sin(Roll) * .025f;
               }
               if (Roll < MathHelper.ToRadians(-90) && Roll >= MathHelper.ToRadians(-180))
               {
                   Roll += ((float)Math.Cos(Roll) * -.009000f*-1);
                   Yaw += (float)Math.Sin(Roll) * .025f;
               }

               
               Position += Vector3.Transform(Velocity,Rotation) * .0017f * SpeedMultiplier;
              
           }
           
       }
       public void SetDiscInfo(CustomDisc DiscInfo)
       {
           SetTexture(DiscInfo.Texture);
           BalancingCoeffiecent = DiscInfo.Stability *.75f;
           if (BalancingCoeffiecent == 0)
               BalancingCoeffiecent = .25f *.6f;
           OriginalBalancingCoeffiecent = BalancingCoeffiecent;
           PowerMultiplier = DiscInfo.MaxDistance / 450;
           if(DiscInfo.MaxDistance > 250)
            PowerMultiplier = ((DiscInfo.MaxDistance / (1.30f*PowerMultiplier + 1.30f)) / MaxVelocity);
           else if (DiscInfo.MaxDistance > 100)
               PowerMultiplier = ((DiscInfo.MaxDistance / (3.05f * PowerMultiplier + .45f)) / MaxVelocity);
           else
           {
               PowerMultiplier = ((DiscInfo.MaxDistance / (.7f * PowerMultiplier + .7f)) / MaxVelocity);
               LiftCoeffiecient = 1.0f;
               Putter = .2f;
           }
           
           MaxVelocity = 100 * ((.1f * ((DiscInfo.MaxDistance / 450) * (DiscInfo.MaxDistance / 450))) + .9f);
           System.Diagnostics.Debug.Print("Maxvelocity = " + MaxVelocity.ToString() + "  PowerMultiplier = " + PowerMultiplier.ToString());
           PowerMultiplier *= -1;

       }

    }

}
    


